package com.fastloan.mgt.application.approve.service.impl;

import com.fastloan.common.BasicServiceImpl;
import com.fastloan.mgt.application.approve.dao.ApplicationApproveMapper;
import com.fastloan.mgt.application.approve.model.ApplicationApprove;
import com.fastloan.mgt.application.approve.model.ApplicationApproveFile;
import com.fastloan.mgt.application.approve.model.ApplicationApproveHistory;
import com.fastloan.mgt.application.approve.model.ApplicationApproveTemplate;
import com.fastloan.mgt.application.approve.model.vo.ApplicationApproveVO;
import com.fastloan.mgt.application.approve.service.ApplicationApproveFileService;
import com.fastloan.mgt.application.approve.service.ApplicationApproveHistoryService;
import com.fastloan.mgt.application.approve.service.ApplicationApproveService;
import com.fastloan.mgt.application.approve.service.ApplicationApproveTemplateService;
import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.model.ApplicationVo;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.processcontrol.base.service.ProcessDispatcher;
import com.fastloan.safe.mgt.sys.model.CmuSysFile;
import com.fastloan.safe.mgt.sys.service.CmSysFileService;
import com.fastloan.utils.DozerUtil;
import com.kawins.supers.table.manager.DataTable;
import org.kie.api.KieBase;
import org.kie.api.cdi.KBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.fastloan.mgt.application.base.enums.ApplicationStatusEnum.APP_APPROVE_REJECT;
import static com.fastloan.mgt.product.enums.ProductEnum.FORBIDDEN;
import static com.fastloan.mgt.product.enums.ProductEnum.PUBLISHED;
import static com.fastloan.mgt.product.enums.ProductEnum.UNPUBLISHED;
import static java.util.stream.Collectors.toList;

/**
 * @author admins
 * createTime 2017/11/09
 */
@Service
public class ApplicationApproveServiceImpl extends BasicServiceImpl<ApplicationApprove> implements ApplicationApproveService {
    @Autowired
    private ApplicationApproveMapper applicationApproveMapper;

    @Autowired
    private ApplicationApproveTemplateService applicationApproveTemplateService;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private ApplicationApproveFileService applicationApproveFileService;

    @Autowired
    private CmSysFileService cmSysFileService;

    @Autowired
    private ApplicationApproveHistoryService applicationApproveHistoryService;

    @KBase("kBase")
    private KieBase kieBase;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void initialize(String applicationId) {
        Example example = new Example(ApplicationApproveTemplate.class);
        example.createCriteria().andEqualTo("applicationId", applicationId)
                .andEqualTo("initiateStatus", UNPUBLISHED.getType());
        List<ApplicationApproveTemplate> approveTemplateList = applicationApproveTemplateService.selectByExample(example);
        approveTemplateList.stream()
                .map(ApplicationApproveTemplate::getTemplateId)
                .forEach(tempId -> {
                    List<String> approveUserIds = applicationApproveTemplateService.queryApproveUserIdByTemplateId(tempId);
                    List<List<ApplicationApprove>> listList = pageApprove(tempId, approveUserIds);
                    listList.forEach(applicationApproveMapper::insertList);
                });
        log.debug("审批专家插入完成, 进件id:{}", applicationId);
    }

    /**
     * 插入审批初始化数据
     * @param tempId
     * @param approveUserIds
     * @return
     */
    private List<List<ApplicationApprove>> pageApprove(String tempId, List<String> approveUserIds) {
        return approveUserIds.stream()
                .map(approveUserIdList ->
                        Arrays.stream(approveUserIdList.split(","))
                                .map(approveUserId -> {
                                    ApplicationApprove applicationApprove = new ApplicationApprove();
                                    applicationApprove.setCreateTime(new Date());
                                    applicationApprove.setTemplateId(tempId);
                                    applicationApprove.setApproveStatus(UNPUBLISHED.getType());
                                    log.debug("插入审批专家id:{}, 模板id{}, 创建时间{}", approveUserId, tempId, LocalDateTime.now());
                                    return applicationApprove.setApproveUserId(approveUserId);
                                }).collect(toList())
                ).collect(toList());
    }

    /**
     *提交审批
     * @param applicationApprove
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitApprove(ApplicationApprove applicationApprove) {
        updateByPrimaryKeySelective(applicationApprove);
        log.debug("提交审批, 审批人{}, 审批金额{}, 审批利率{}, 审批结果{}( 1 通过, 2 拒绝), 备注{}, 审批时间{}",
                applicationApprove.getApproveUserId(), applicationApprove.getApproveAmount()
        ,applicationApprove.getApproveRate(), applicationApprove.getApproveStatus(), applicationApprove.getApproveComment()
        , LocalDateTime.now());
        ApplicationApproveHistory applicationApproveHistory = new ApplicationApproveHistory();
        applicationApproveHistory.setCreateTime(new Date());
        applicationApproveHistory.setAppApproveId(applicationApprove.getAppApproveId());
        applicationApproveHistoryService.insertSelective(applicationApproveHistory);
        startDrools(applicationApprove.getAppApproveId());
        finalDrools(applicationApprove.getAppApproveId());
        ifHaveFlow(applicationApprove.getTemplateId());
    }

    /**
     * 是否继续执行流程
     *
     * @param templateId
     */
    private void ifHaveFlow(String templateId) {
        ApplicationApproveTemplate approveTemplate = applicationApproveTemplateService.selectByPrimaryKey(templateId);
        Application application = applicationService.selectByPrimaryKey(approveTemplate.getApplicationId());
        if (approveTemplate.getApproveStatus().equals(PUBLISHED.getType())) {
            ProcessDispatcher.executeEnd(application.getProcessId(), true);
        } else if (approveTemplate.getApproveStatus().equals(FORBIDDEN.getType())) {
            ProcessDispatcher.executeEnd(application.getProcessId(), false);
            application.setApplicationStatus(APP_APPROVE_REJECT.getType());
            applicationService.updateByPrimaryKeySelective(application);
        }
    }

    /**
     * 查询进件审批详情
     * @param appApproveId
     * @return
     */
    @Override
    public ApplicationApproveVO queryApplicationApprove(String appApproveId) {
        ApplicationApprove applicationApprove = selectByPrimaryKey(appApproveId);
        ApplicationApproveVO approveVO = DozerUtil.map(applicationApprove, ApplicationApproveVO.class);
        ApplicationApproveFile applicationApproveFile = new ApplicationApproveFile();
        applicationApproveFile.setAppApproveId(applicationApprove.getAppApproveId());
        String applicationId = applicationApproveTemplateService.selectByPrimaryKey(applicationApprove.getTemplateId())
                .getApplicationId();
        ApplicationVo applicationVo = applicationService.selectApplicationVo(applicationId);
        approveVO.setApplicationVo(applicationVo);
        queryApproveFile(approveVO, applicationApproveFile);
        return approveVO;
    }

    /**
     * 查询审批文件
     *
     * @param approveVO
     * @param applicationApproveFile
     */
    private void queryApproveFile(ApplicationApproveVO approveVO, ApplicationApproveFile applicationApproveFile) {
        List<ApplicationApproveFile> fileList = applicationApproveFileService.select(applicationApproveFile);
        if (fileList != null && !fileList.isEmpty()) {
            List<CmuSysFile> cmuSysFileList = fileList.stream()
                    .map(ApplicationApproveFile::getFileId)
                    .map(cmSysFileService::selectByPrimaryKey)
                    .collect(toList());
            approveVO.setApproveFileList(cmuSysFileList);
        }
    }

    @Override
    @DataTable(name = "queryAppApproveList")
    public List<ApplicationApproveVO> queryAppApproveList(Map<String, Object> map) {
        return applicationApproveMapper.queryAppApproveList(map);
    }

    /**
     * 执行审批规则验证是否通过审批
     *
     * @param appApproveId
     */
    private void startDrools(String appApproveId) {
        ApproveDroolsModel approveDroolsModel = new ApproveDroolsModel(appApproveId).invoke();
        List<ApplicationApprove> applicationApproveList = approveDroolsModel.getApplicationApproveList();
        List<ApplicationApproveTemplate> applicationApproveTemplates = approveDroolsModel.getApplicationApproveTemplates();
        ApplicationApproveTemplate template = approveDroolsModel.getTemplate();
        long count = applicationApproveList.stream()
                .filter(applicationApprove -> applicationApprove.getApproveStatus().equals(FORBIDDEN.getType()))
                .count();
        if (count > UNPUBLISHED.getType()) {
            applicationApproveTemplates.forEach(applicationApproveTemplateService::updateByPrimaryKeySelective);
        } else {
            applicationApproveTemplateService.updateByPrimaryKeySelective(template);
        }
    }

    /**
     * 最终审批规则
     * @param appApproveId
     */
    private void finalDrools(String appApproveId) {
        ApproveDroolsModel approveDroolsModel = new ApproveDroolsModel(appApproveId).invoke();
        Application application = approveDroolsModel.getApplication();
        applicationService.updateByPrimaryKeySelective(application);
    }

    @Override
    public List<ApplicationApproveVO> queryApprovePlan(String applicationId) {
        return applicationApproveMapper.queryApprovePlan(applicationId);
    }

    private class ApproveDroolsModel {
        private String appApproveId;
        private List<ApplicationApprove> applicationApproveList;
        private ApplicationApproveTemplate template;
        private List<ApplicationApproveTemplate> applicationApproveTemplates;
        private Application application;

        ApproveDroolsModel(String appApproveId) {
            this.appApproveId = appApproveId;
        }

        List<ApplicationApprove> getApplicationApproveList() {
            return applicationApproveList;
        }

        ApplicationApproveTemplate getTemplate() {
            return template;
        }

        List<ApplicationApproveTemplate> getApplicationApproveTemplates() {
            return applicationApproveTemplates;
        }

        public Application getApplication() {
            return application;
        }

        ApproveDroolsModel invoke() {
            String templateId = applicationApproveMapper.selectByPrimaryKey(appApproveId).getTemplateId();
            ApplicationApprove applicationApprove = new ApplicationApprove();
            applicationApprove.setTemplateId(templateId);
            applicationApproveList = select(applicationApprove);
            template = applicationApproveTemplateService.selectByPrimaryKey(templateId);
            Example example = new Example(ApplicationApproveTemplate.class);
            example.createCriteria().andEqualTo("applicationId", template.getApplicationId());
            applicationApproveTemplates = applicationApproveTemplateService.selectByExample(example);
            application = applicationService.selectByPrimaryKey(template.getApplicationId());
            KieSession kieSession = kieBase.newKieSession();
            kieSession.insert(application);
            kieSession.insert(template);
            kieSession.setGlobal("approveList", applicationApproveList);
            kieSession.setGlobal("templateApproveList", applicationApproveTemplates);
            kieSession.fireAllRules();
            kieSession.dispose();
            return this;
        }
    }
}
